﻿using System;
using System.Runtime.InteropServices;

namespace Alex.Library.Win32
{
    /// <summary>
    /// Win32 SDK中与消息相关的API
    /// </summary>
    public sealed class MessageApi
    {
        #region delegates

        /// <summary>
        /// 用于SetWindowLong函数的自定义函数委托(指针)
        /// </summary>
        /// <param name="hWnd">窗口句柄</param>
        /// <param name="nCode">消息值</param>
        /// <param name="WParam">由nCode决定的信息</param>
        /// <param name="LParam">由nCode决定的信息</param>
        /// <returns></returns>
        public delegate int CallWindowProcDelegate(IntPtr hWnd, int nCode, IntPtr WParam, IntPtr LParam);

        /// <summary>
        /// 钩子的回调函数
        /// </summary>
        /// <param name="code">消息值</param>
        /// <param name="wParam">由code决定的信息</param>
        /// <param name="lParam">由code决定的信息</param>
        /// <returns></returns>
        public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);

        #endregion

        /// <summary>
        /// 获取窗口信息
        /// </summary>
        /// <param name="hwindow">欲为其获取信息的窗口的句柄</param>
        /// <param name="uIndex">
        /// 欲取回的信息，可以是下述任何一个常数：
        /// GWL_EXSTYLE: 扩展窗口样式        
        /// GWL_STYLE: 窗口样式       
        /// GWL_WNDPROC: 该窗口的窗口函数的地址
        /// GWL_HINSTANCE: 拥有窗口的实例的句柄
        /// GWL_HWNDPARENT: 该窗口之父的句柄。不要用SetWindowWord来改变这个值
        /// GWL_ID: 对话框中一个子窗口的标识符
        /// GWL_USERDATA: 含义由应用程序规定
        /// DWL_DLGPROC: 这个窗口的对话框函数地址
        /// DWL_MSGRESULT: 在对话框函数中处理的一条消息返回的值
        /// DWL_USER: 含义由应用程序规定
        /// </param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern int GetWindowLong(IntPtr hwindow, WindowLongCode uIndex);

        /// <summary>
        /// 设置窗口信息
        /// </summary>
        /// <param name="hwindow">欲为其设置信息的窗口的句柄</param>
        /// <param name="unindex">
        /// 欲取回的信息，可以是下述任何一个常数：
        /// GWL_EXSTYLE: 扩展窗口样式        
        /// GWL_STYLE: 窗口样式       
        /// GWL_WNDPROC: 该窗口的窗口函数的地址
        /// GWL_HINSTANCE: 拥有窗口的实例的句柄
        /// GWL_HWNDPARENT: 该窗口之父的句柄。不要用SetWindowWord来改变这个值
        /// GWL_ID: 对话框中一个子窗口的标识符
        /// GWL_USERDATA: 含义由应用程序规定
        /// DWL_DLGPROC: 这个窗口的对话框函数地址
        /// DWL_MSGRESULT: 在对话框函数中处理的一条消息返回的值
        /// DWL_USER: 含义由应用程序规定
        /// </param>
        /// <param name="lnewvalue">设置的值</param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern int SetWindowLong(IntPtr hwindow, WindowLongCode unindex, CallWindowProcDelegate lnewvalue);

        /// <summary>
        /// 调用窗口消息处理函数
        /// </summary>
        /// <param name="lpPrevWndFunc">处理函数地址</param>
        /// <param name="hWnd">窗口句柄</param>
        /// <param name="Msg">消息值</param>
        /// <param name="wParam">由Msg决定的信息</param>
        /// <param name="lParam">由Msg决定的信息</param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern int CallWindowProc(int lpPrevWndFunc, IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);        

        /// <summary>
        /// 给指定的窗口发消息
        /// </summary>
        /// <param name="hwnd">要接收消息的那个窗口的句柄</param>
        /// <param name="wMsg">消息的标识符</param>
        /// <param name="wParam">指定附加的消息特定信息</param>
        /// <param name="lParam">指定附加的消息特定信息</param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern long SendMessage(Int32 hwnd, int wMsg, IntPtr wParam, IntPtr lParam);

        /// <summary>
        /// 从调用线程的消息队列里取得一个消息并将其放于指定的结构。此函数可取得与指定窗口联系的消息和由PostThreadMesssge寄送的线程消息。
        /// 此函数接收一定范围的消息值。GetMessage不接收属于其他线程或应用程序的消息。获取消息成功后，线程将从消息队列中删除该消息。
        /// 函数会一直等待直到有消息到来才有返回值。
        /// </summary>
        /// <param name="lpMsg">指向MSG结构的指针，该结构从线程的消息队列里接收消息信息。</param>
        /// <param name="hwnd">取得其消息的窗口的句柄。这是一个有特殊含义的值（NULL）。GetMessage为任何属于调用线程的窗口检索消息，线程消息通过PostThreadMessage寄送给调用线程。 </param>
        /// <param name="wMsgFilterMin">指定被检索的最小消息值的整数。 </param>
        /// <param name="wMsgFilterMax">指定被检索的最大消息值的整数。 </param>
        /// <returns>
        /// 如果函数取得WM_QUIT之外的其他消息，返回非零值。如果函数取得WM_QUIT消息，返回值是零。如果出现了错误，返回值是-1。
        /// 例如，当hWnd是无效的窗口句柄或lpMsg是无效的指针时。若想获得更多的错误信息，请调用GetLastError函数。
        /// </returns>
        [DllImport("user32.dll")]
        public static extern int GetMessage(out LPMSG lpMsg, int hwnd, int wMsgFilterMin, int wMsgFilterMax);

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hWnd">
        /// 接收消息的那个窗口的句柄。如设为HWND_BROADCAST，表示投递给系统中的所有顶级窗口。
        /// 如设为零，表示投递一条线程消息（参考PostThreadMessage）
        /// </param>
        /// <param name="Msg">消息标识符</param>
        /// <param name="wParam">指定附加的消息特定信息</param>
        /// <param name="lParam">指定附加的消息特定信息</param>
        /// <returns></returns>
        [DllImport("user32.dll")]
        public static extern bool PostMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);

        /// <summary>
        /// 广播消息
        /// </summary>
        /// <param name="dw">
        /// 下述常数的一个或多个:
        /// BSF_FLUSHDISK
        /// 每次处理完一条消息后，都对磁盘进行刷新（将未存盘的数据存下来
        /// BSF_FORCEIFHUNG
        /// 如目标处于挂起状态，则在设定的超时后到期返回
        /// BSF_IGNORECURRENTTASK
        /// 发送任务不接收消息
        /// BSF_LPARAMBUFFER        
        /// </param>
        /// <param name="pdw">
        /// 下述常数的一个或多个:
        /// BSF_ALLCOMPONENTS
        /// 消息进入能够接收消息的每一个系统组件
        /// BSF_APPLICATIONS
        /// 消息到达应用程序
        /// BSF_INSTALLABLEDRIVERS
        /// 消息到达可安装的驱动程序
        /// BSF_NETDRIVERS
        /// 消息到达网络驱动程序
        /// BSF_VXDS
        /// 消息到达系统设备驱动程序
        /// </param>
        /// <param name="un">消息编号</param>
        /// <param name="wParam">由消息决定</param>
        /// <param name="lParam">
        /// 由消息决定。如指定了BSF_LPARAMBUFFER，这就是位于调用进程地址空间的一个内存缓冲区的地址，而且缓冲区的第一个16位字包含了缓冲区的长度
        /// lParam指向一个内存缓冲区 -  BSF_NOHANG
        /// 跳过被挂起的所有进程
        /// BSF_POSTMESSAGE
        /// 投递消息。不与BSF_LPARAMBUFFER和BSF_QUERY兼容
        /// BSF_QUERY
        /// 将消息顺序发给进程，只有前一个返回TRUE时，才进入下一个进程
        /// </param>
        /// <returns></returns>
        [DllImport("user32.dll", EntryPoint = "BroadcastSystemMessage")]
        public static extern int BroadcastSystemMessage(int dw, ref int pdw, int un, int wParam, int lParam);

        /// <summary>
        /// 注册消息
        /// </summary>
        /// <param name="lpString">注册消息名称</param>
        /// <returns></returns>
        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern uint RegisterWindowMessage(string lpString);

        /// <summary>
        /// 设置系统钩子
        /// </summary>
        /// <param name="idHook">钩子的类型，即它处理的消息类型 </param>
        /// <param name="lpfn">钩子回调函数</param>
        /// <param name="pInstance">
        /// 应用程序实例的句柄。标识包含lpfn所指的函数的DLL。
        /// 如果threadId 标识当前进程创建的一个线程，
        /// 而且函数代码位于当前进程，pInstance必须为NULL。
        /// 可以很简单的设定其为本应用程序的实例句柄。(通常可为0)
        /// </param>
        /// <param name="threadId">
        /// 安装的钩子子程相关联的线程的标识符。
        /// 如果为0，钩子回调函数与所有的线程关联，即为全局钩子。 
        /// </param>
        /// <returns>成功设置的钩子的地址</returns>
        [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern IntPtr SetWindowsHookEx(HookType idHook, HookProc lpfn, IntPtr pInstance, int threadId);

        /// <summary>
        /// 调用钩子链表所指的下一个钩子回调函数
        /// </summary>
        /// <param name="pHookHandle">为当前钩子的句柄，由SetWindowsHookEx()函数返回。</param>
        /// <param name="nCode">为传给钩子函数的消息代码。 </param>
        /// <param name="wParam">与nCode消息有关</param>
        /// <param name="lParam">与nCode消息有关</param>
        /// <returns>返回钩子链中下一个钩子函数的返回值， 返回值的类型依赖于钩子的类型</returns>
        [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(IntPtr pHookHandle, int nCode, Int32 wParam, IntPtr lParam);

        /// <summary>
        /// 卸载钩子
        /// </summary>
        /// <param name="pHookHandle">钩子的地址</param>
        /// <returns>是否成功卸载钩子</returns>
        [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(IntPtr pHookHandle);
    }
}
